/**************************************************************************//**
 * @item     CosyOS-II Kernel
 * @file     sv_task.c
 * @brief    任务服务（仅在任务中调用）
 * @author   迟凯峰
 * @version  V1.0.1
 * @date     2023.10.26
 ******************************************************************************/

#include "os_var.h"
#include "os_api.h"
#include "ur_api.h"



/*
 * 任务服务专用
 */

/* 任务服务中触发任务调度 */
static void _task_scheduling_(void)
{
	s_sign_scheduling = true;
	mPendSV_Set;
	uExitCritical;
	while(s_sign_scheduling);
}

/* 进入任务临界区并返回真 */
s_bool_t su_enter_critical(void)
{
	uEnterCritical;
	return true;
}

/* 退出任务临界区并返回真 */
s_bool_t su_exit_critical(void)
{
	uExitCritical;
	return true;
}



/*
 * 任务服务开始
 */

/* 任务调度 */
void su_task_scheduling(void)
{
	uEnterCritical;
	_task_scheduling_();
}

/* 启动任务 */
s_ecode_t su_startup_task(s_taskhand_tsp hand, s_u8_t status)
{
	static s_tid_t _SYS_MEM_ tid = 0;
	if(!hand->tid){
		tid++;
		hand->tid = tid;
	}
	#if SYSCFG_TASKCREATEMODE == __STATIC__ \
	 || SYSCFG_TASKCREATEMODE == __BALANCE__
	hand->status = status;
	#elif SYSCFG_TASKCREATEMODE == __DYNAMIC__
	s_task_status0 = status;
	#endif
	s_task_starter = hand;
	_task_scheduling_();
	return s_sign_return ? s_startup_code : (s_ecode_t)s_task_current->blocktype;
}

/* 挂起任务 */
s_ecode_t su_suspend_task(s_tasknode_tsp node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(node == NULL){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	#endif
	if(node->status < OS_STATUS_SUSPENDED){
		node->status |= OS_STATUS_SUSPENDED;
		if(node == s_task_current){
			_task_scheduling_();
		}
		else{
			uExitCritical;
		}
		return OS_ECODE_NOERROR;
	}
	if(node->status & OS_STATUS_SUSPENDED){
		uExitCritical;
		return OS_ECODE_TASKSUSPENDED;
	}
	if(node->status & OS_STATUS_STOPPED){
		uExitCritical;
		return OS_ECODE_TASKSTOPPED;
	}
	if(node->status == OS_STATUS_DELETED){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	else{
		uExitCritical;
		return OS_ECODE_DONOTKNOW;
	}
}

/* 恢复任务 */
s_ecode_t su_resume_task(s_tasknode_tsp node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(node == NULL){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	#endif
	if(node->status & OS_STATUS_SUSPENDED){
		node->status &= (~OS_STATUS_SUSPENDED & 0xFF);
		if(node->status <= OS_STATUS_FLOATING && node->pri > s_task_current->pri){
			_task_scheduling_();
		}
		else{
			uExitCritical;
		}
		return OS_ECODE_NOERROR;
	}
	if(node->status < OS_STATUS_STOPPED){
		uExitCritical;
		return OS_ECODE_TASKUNSUSPENDED;
	}
	if(node->status & OS_STATUS_STOPPED){
		uExitCritical;
		return OS_ECODE_TASKSTOPPED;
	}
	if(node->status == OS_STATUS_DELETED){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	else{
		uExitCritical;
		return OS_ECODE_DONOTKNOW;
	}
}

/* 恢复指定任务并挂起自身任务 */
s_ecode_t su_resume_suspend(s_tasknode_tsp node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(node == NULL){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	#endif
	if(node->status & OS_STATUS_SUSPENDED){
		node->status &= (~OS_STATUS_SUSPENDED & 0xFF);
	}
	if(node->status <= OS_STATUS_FLOATING){
		s_task_current->status |= OS_STATUS_SUSPENDED;
		_task_scheduling_();
		return OS_ECODE_NOERROR;
	}
	if(node->status < OS_STATUS_STOPPED){
		uExitCritical;
		return OS_ECODE_TASKNOTREADY;
	}
	if(node->status & OS_STATUS_STOPPED){
		uExitCritical;
		return OS_ECODE_TASKSTOPPED;
	}
	if(node->status == OS_STATUS_DELETED){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	else{
		uExitCritical;
		return OS_ECODE_DONOTKNOW;
	}
}

/* 删除任务 */
s_ecode_t su_delete_task(s_tasknode_tsp node)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(node == NULL){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	#endif
	if(node->status < OS_STATUS_DELETED){
		node->status = OS_STATUS_DELETED;
		if(node == s_task_current){
			_task_scheduling_();
		}
		else{
			uExitCritical;
		}
		return OS_ECODE_NOERROR;
	}
	if(node->status == OS_STATUS_DELETED){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	else{
		uExitCritical;
		return OS_ECODE_DONOTKNOW;
	}
}

/* 设置任务优先级 */
s_ecode_t su_set_taskpri(s_tasknode_tsp node, s_u8_t pri)
{
	#if SYSCFG_TASKCREATEMODE == __DYNAMIC__
	if(node == NULL){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	#endif
	if(node->status < OS_STATUS_STOPPED){
		if(node->pri != pri){
			node->pri = pri;
			sSetTaskPri(node);
			if(pri > s_task_current->pri && node->status <= OS_STATUS_FLOATING){
				_task_scheduling_();
			}
			else{
				uExitCritical;
			}
			return OS_ECODE_NOERROR;
		}
		else{
			uExitCritical;
			return OS_ECODE_TASKPRIUNCHANGED;
		}
	}
	if(node->status & OS_STATUS_STOPPED){
		uExitCritical;
		return OS_ECODE_TASKSTOPPED;
	}
	if(node->status == OS_STATUS_DELETED){
		uExitCritical;
		return OS_ECODE_TASKNOTSTARTED;
	}
	else{
		uExitCritical;
		return OS_ECODE_DONOTKNOW;
	}
}

/* 设置阻塞（时间）*/
s_bool_t su_set_block(s_tasknode_tsp node, s_delay_t tick)
{
	if(node->status == OS_STATUS_BLOCKED || node->status == OS_STATUS_FLOATING){
		s_delay_loader[node->tid] = tick;
		if(!tick){
			node->status = OS_STATUS_READY;
			if(node->pri > s_task_current->pri){
				_task_scheduling_();
			}
			else{
				uExitCritical;
			}
		}
		else{
			uExitCritical;
		}
		return true;
	}
	else{
		uExitCritical;
		return false;
	}
}

/* 清除阻塞（状态）*/
s_bool_t su_clear_block(s_tasknode_tsp node)
{
	if(node->status == OS_STATUS_BLOCKED || node->status == OS_STATUS_FLOATING){
		s_delay_loader[node->tid] = 0;
		node->status = OS_STATUS_READY;
		if(node->pri > s_task_current->pri){
			_task_scheduling_();
		}
		else{
			uExitCritical;
		}
		return true;
	}
	else{
		uExitCritical;
		return false;
	}
}

/* 自身任务延时 */
void su_delay(s_delay_t tick)
{
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_DELAY;
	_task_scheduling_();
}



/*
 * 互斥信号量
 */
#if SYSCFG_MUTEX == __ENABLED__
/* 获取 */
s_bool_t su_take_mutex(s_mutex_tsp mut, s_delay_t tick)
{
	if(!mut->mutex) goto __RET_TRUE1;
	if(s_task_current == mut->node) goto __RET_TRUE2;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_MUTEX | 0x0F;
	s_task_current->ptr = mut;
	if(s_task_current->pri > mut->node->pri){
		mut->node->pri = s_task_current->pri;
		sSetTaskPri(mut->node);
	}
	_task_scheduling_();
	uEnterCritical;
	mut = (s_mutex_tsp)s_task_current->ptr;
	if(!mut->mutex) goto __RET_TRUE1;
	
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE1:
	mut->node = s_task_current;
	mut->oldpri = s_task_current->pri;
	
__RET_TRUE2:
	mut->mutex++;
	uExitCritical;
	return true;
}

/* 释放 */
s_ecode_t su_give_mutex(s_mutex_tsp mut)
{
	if(!mut->mutex){
		uExitCritical;
		return OS_ECODE_MUTEXISGIVE;
	}
	if(s_task_current == mut->node){
		mut->mutex--;
		if(!mut->mutex){
			if(s_task_current->pri > mut->oldpri){
				s_task_current->pri = mut->oldpri;
				sSetTaskPri(s_task_current);
				_task_scheduling_();
			}
			else{
				uExitCritical;
			}
		}
		else{
			uExitCritical;
		}
		return OS_ECODE_NOERROR;
	}
	else{
		uExitCritical;
		return OS_ECODE_NOPERMISSION;
	}
}

#endif



/*
 * 二值信号量
 */
#if SYSCFG_BINARY == __ENABLED__
/* 等待 */
s_bool_t su_wait_binary(s_bool_t _OBJ_MEM_ *bin, s_delay_t tick)
{
	if(*bin) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_BINARY | sizeof(*bin);
	s_task_current->ptr = bin;
	_task_scheduling_();
	uEnterCritical;
	bin = (s_bool_t *)s_task_current->ptr;
	if(*bin) goto __RET_TRUE;
	
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE:
	uExitCritical;
	return true;
}

/* 获取 */
s_bool_t su_take_binary(s_bool_t _OBJ_MEM_ *bin, s_delay_t tick)
{
	if(*bin) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_BINARY | sizeof(*bin);
	s_task_current->ptr = bin;
	_task_scheduling_();
	uEnterCritical;
	bin = (s_bool_t *)s_task_current->ptr;
	if(*bin) goto __RET_TRUE;
	
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE:
	*bin = false;
	uExitCritical;
	return true;
}

#endif



/*
 * 计数信号量
 */
#if SYSCFG_SEMAPHORE == __ENABLED__
/* 获取 */
s_bool_t su_take_semaphore(s_sem_tsp sem, s_delay_t tick)
{
	if(sem->counter) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_SEMAPHORE | sizeof(sem->counter);
	s_task_current->ptr = sem;
	_task_scheduling_();
	uEnterCritical;
	sem = (s_sem_tsp)s_task_current->ptr;
	if(sem->counter) goto __RET_TRUE;
	
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE:
	(sem->counter)--;
	uExitCritical;
	return true;
}

/* 释放 */
void su_give_semaphore(s_sem_tsp sem)
{
	if(sem->counter < sem->maximum){
		sem->counter++;
	}
	uExitCritical;
}

#endif



/*
 * 飞信
 */
#if SYSCFG_FETION == __ENABLED__
/* 接收飞信 */
static m_fetion_t _recv_fetion_(m_fetion_t _OBJ_MEM_ *ft)
{
	m_fetion_t fetion = *ft;
	*ft = false;
	uExitCritical;
	return fetion;
}

m_fetion_t su_recv_fetion(m_fetion_t _OBJ_MEM_ *ft, s_delay_t tick)
{
	if(*ft) goto __RET_TION;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_FETION | sizeof(*ft);
	s_task_current->ptr = ft;
	_task_scheduling_();
	uEnterCritical;
	ft = (m_fetion_t *)s_task_current->ptr;
	
__RET_TION:
	return _recv_fetion_(ft);
	
__RET_FALSE:
	uExitCritical;
	return false;
}

#endif



/*
 * 私信
 */
#if SYSCFG_TASKMSG == __ENABLED__
/* 接收私信 */
s_bool_t su_recv_taskmsg(m_taskmsg_t _OBJ_MEM_ *nmf, s_delay_t tick)
{
	if(*nmf) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_DIRMSG | sizeof(*nmf);
	s_task_current->ptr = nmf;
	_task_scheduling_();
	uEnterCritical;
	nmf = (m_taskmsg_t *)s_task_current->ptr;
	if(*nmf) goto __RET_TRUE;
	
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE:
	*nmf = false;
	return true;
}

#endif



/*
 * 消息邮箱
 */
#if SYSCFG_MAILBOX == __ENABLED__
/* 接收邮件 */
s_bool_t su_recv_mail(s_bool_t _OBJ_MEM_ *gf, s_delay_t tick)
{
	if(*gf) goto __RET_TRUE;
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_MAIL | sizeof(*gf);
	s_task_current->ptr = gf;
	_task_scheduling_();
	uEnterCritical;
	gf = (s_bool_t *)s_task_current->ptr;
	if(*gf) goto __RET_TRUE;
	
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE:
	*gf = false;
	return true;
}

/* 发送邮件 */
void su_send_mail(void _OBJ_MEM_ *gm, void *lm, size_t size, s_bool_t _OBJ_MEM_ *gf)
{
	static s_mbox_ts accessor;
	accessor.gm = gm;
	#if SYSCFG_MAILBOX_ACCESSMECHANISM == 1
	accessor.lm = lm;
	accessor.lf = true;
	#endif
	sWrite_MBoxAccessor(&accessor);
	s_memcpy(gm, lm, size);
	sWrite_MBoxAccessor(NULL);
	#if SYSCFG_MAILBOX_ACCESSMECHANISM == 0
	*gf = true;
	#elif SYSCFG_MAILBOX_ACCESSMECHANISM == 1
	*gf = accessor.lf;
	#endif
	uExitCritical;
}

#endif



/*
 * 消息队列
 */
#if SYSCFG_MSGQUEUE == __ENABLED__
/* 接收消息 */
static void *_recv_msg_(void *msg)
{
	uExitCritical;
	return msg;
}

void *su_recv_msg(s_msgqueue_tsp queue, s_delay_t tick)
{
	void *msg;
	s_msgnode_tsp node;
	queue->mutex = false;
	if(queue->counter) goto __RECV_MSG;
	queue->mutex = true;
	if(!tick) goto __RET_NULL;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_MSG | sizeof(queue->counter);
	s_task_current->ptr = queue;
	_task_scheduling_();
	uEnterCritical;
	queue = (s_msgqueue_tsp)s_task_current->ptr;
	queue->mutex = false;
	if(!queue->counter) goto __FREE_MUTEX;
	
__RECV_MSG:
	if(queue->type == __DYNAMIC__){
		sRecvMsg_Dynamic(msg);
	}
	else{
		sRecvMsg_Static(msg);
	}
	queue->mutex = true;
	return _recv_msg_(msg);
	
__FREE_MUTEX:
	queue->mutex = true;
	
__RET_NULL:
	uExitCritical;
	return NULL;
}

/* 发送消息 */
s_ecode_t su_send_msg(s_msgqueue_tsp queue, void *msg)
{
	queue->mutex = false;
	if(queue->counter == queue->len){
		queue->mutex = true;
		#if SYSCFG_DEBUGGING == __ENABLED__
		s_alarm.overflow_msgqueue = true;
		#endif
		uExitCritical;
		return OS_ECODE_OVERFLOW_MSGQUEUE;
	}
	if(queue->type == __DYNAMIC__){
		s_msgnode_tsp node = NULL;
		node = (s_msgnode_tsp)s_malloc(sizeof(s_msgnode_ts));
		if(node == NULL){
			queue->mutex = true;
			#if SYSCFG_DEBUGGING == __ENABLED__
			s_fault.mallocfailed_msgnode = true;
			#endif
			uExitCritical;
			return OS_ECODE_MALLOCFAIL_MSGNODE;
		}
		sSendMsg_Dynamic(msg);
	}
	else{
		sSendMsg_Static(msg);
	}
	queue->mutex = true;
	uExitCritical;
	return OS_ECODE_NOERROR;
}

#endif



/*
 * 事件标志组
 */
#if SYSCFG_FLAGGROUP == __ENABLED__
/* 查询标志组 */
s_bool_t su_query_group(void _OBJ_MEM_ *p, s_u8_t size)
{
	switch(size){
	case 1: if(*(s_u8_t  *)p) goto __RET_TRUE; break;
	case 2: if(*(s_u16_t *)p) goto __RET_TRUE; break;
	case 4: if(*(s_u32_t *)p) goto __RET_TRUE; break;
	}
	uExitCritical;
	return false;
	
__RET_TRUE:
	uExitCritical;
	return true;
}

/* 等待标志组 */
s_bool_t su_wait_group(void _OBJ_MEM_ *p, s_u8_t size, s_delay_t tick)
{
	switch(size){
	case 1: if(*(s_u8_t  *)p) goto __RET_TRUE; break;
	case 2: if(*(s_u16_t *)p) goto __RET_TRUE; break;
	case 4: if(*(s_u32_t *)p) goto __RET_TRUE; break;
	}
	if(!tick) goto __RET_FALSE;
	
	s_delay_loader[s_task_current->tid] = tick;
	s_task_current->status = OS_STATUS_BLOCKED;
	s_task_current->blocktype = OS_BLOCKED_FLAGGROUP | size;
	s_task_current->ptr = p;
	_task_scheduling_();
	uEnterCritical;
	p = s_task_current->ptr;
	size = s_task_current->blocktype & 0x0F;
	switch(size){
	case 1: if(*(s_u8_t  *)p) goto __RET_TRUE; break;
	case 2: if(*(s_u16_t *)p) goto __RET_TRUE; break;
	case 4: if(*(s_u32_t *)p) goto __RET_TRUE; break;
	}
__RET_FALSE:
	uExitCritical;
	return false;
	
__RET_TRUE:
	uExitCritical;
	return true;
}

#endif



/*
 * 全局变量
 */

/* 全局变量写访问 */
void su_gvar_write(void *gv, void *lv, size_t size)
{
	static s_gvar_ts accessor;
	accessor.gv = gv;
	accessor.lv = lv;
	sWrite_GVarAccessor(&accessor);
	size ? s_memcpy(gv, lv, size) : s_strcpy((char *)gv, (char *)lv);
	sWrite_GVarAccessor(NULL);
	uExitCritical;
}

/* 全局变量自运算 */
void su_gvar_selfope(void *gv, void *lv, s_voidvoid_tfp fp)
{
	static s_gvar_ts accessor;
	accessor.gv = gv;
	accessor.lv = lv;
	sWrite_GVarAccessor(&accessor);
	(*fp)();
	sWrite_GVarAccessor(NULL);
	uExitCritical;
}



/*
 * 动态内存
 */
#if SYSCFG_DYNMEMMGE == __ENABLED__
/* uxalloc */
void _MALLOC_MEM_ *su_xalloc(void _MALLOC_MEM_ *p)
{
	uExitCritical;
	return p;
}

/* 初始化线程内存池 */
s_bool_t su_init_mempool(s_thrmem_tsp p, size_t size)
{
	p->head = p->move = s_malloc(size);
	if(p->head == NULL){
		uExitCritical;
		return false;
	}
	else{
		p->size = size;
		uExitCritical;
		return true;
	}
}

/* 线程内存分配 */
void _MALLOC_MEM_ *su_talloc(s_thrmem_tsp p, size_t size)
{
	if(p->head == NULL || (size_t)p->move - (size_t)p->head + size > p->size){
		return NULL;
	}
	else{
		void _MALLOC_MEM_ *r = p->move;
		p->move = (s_u8_t *)p->move + size;
		return r;
	}
}

#endif
